/**
 * Project name:ads-backend-core
 */
package net.sppan.blog.utils;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.math.NumberUtils;

import com.jfinal.kit.StrKit;

/**
 * Miscellaneous object utility methods the class is writting. from spring source.
 *
 */
public final class ObjectUtils {

	private static final String CHARSET = "UTF-8";

	/**
	 * Return whether the given throwable is a checked exception
	 */
	public static boolean isCheckedException(Throwable ex) {
		return !(ex instanceof RuntimeException || ex instanceof Error);
	}

	/**
	 * return whether the given array is empty
	 */
	public static boolean isEmpty(Object[] array) {
		return (array == null || array.length == 0);
	}

	/**
	 * Check whether the given array contains the given element
	 */
	public static boolean containsElement(Object[] array, Object element) {
		if (array == null) {
			return false;
		}
		boolean cotainsFlag = false;
		for (int i = 0; i < array.length; i++) {
			if (equals(array[i], element)) {
				cotainsFlag = true;
				break;
			}
		}
		return cotainsFlag;
	}

	/**
	 * check if the given objects are equal
	 */
	public static boolean equals(Object o1, Object o2) {
		if (o1 == o2) {
			return true;
		}
		if (o1 == null || o2 == null) {
			return false;
		}
		if (o1.equals(o2)) {
			return true;
		}
		if (o1.getClass().isArray() && o2.getClass().isArray()) {
			if (o1 instanceof Object[] && o2 instanceof Object[]) {
				return Arrays.equals((Object[]) o1, (Object[]) o2);
			}
			if (o1 instanceof boolean[] && o2 instanceof boolean[]) {
				return Arrays.equals((boolean[]) o1, (boolean[]) o2);
			}
			if (o1 instanceof byte[] && o2 instanceof byte[]) {
				return Arrays.equals((byte[]) o1, (byte[]) o2);
			}
			if (o1 instanceof char[] && o2 instanceof char[]) {
				return Arrays.equals((char[]) o1, (char[]) o2);
			}
			if (o1 instanceof double[] && o2 instanceof double[]) {
				return Arrays.equals((double[]) o1, (double[]) o2);
			}
			if (o1 instanceof float[] && o2 instanceof float[]) {
				return Arrays.equals((float[]) o1, (float[]) o2);
			}
			if (o1 instanceof int[] && o2 instanceof int[]) {
				return Arrays.equals((int[]) o1, (int[]) o2);
			}
			if (o1 instanceof long[] && o2 instanceof long[]) {
				return Arrays.equals((long[]) o1, (long[]) o2);
			}
			if (o1 instanceof short[] && o2 instanceof short[]) {
				return Arrays.equals((short[]) o1, (short[]) o2);
			}
		}
		return false;
	}

	/**
	 * Append the given Object to the given array, returning a new array consisting of the input array contents plus the given Object.
	 *
	 * @param array
	 *            []
	 * @param obj
	 */
	public static Object[] addObjectToArray(Object[] array, Object obj) {
		Class<?> compType = Object.class;
		if (array != null) {
			compType = array.getClass().getComponentType();
		} else if (obj != null) {
			compType = obj.getClass();
		}
		int newArrLength = (array != null ? array.length + 1 : 1);
		Object[] newArr = (Object[]) Array.newInstance(compType, newArrLength);
		if (array != null) {
			System.arraycopy(array, 0, newArr, 0, array.length);
		}
		newArr[newArr.length - 1] = obj;
		return newArr;
	}

	/*
	 * public static void copyProperties(Object dest, Object orig) throws IllegalAccessException, InvocationTargetException { BeanUtils.copyProperties(dest, orig); }
	 * 
	 * public static void copyProperty(Object bean, String name, Object value) throws IllegalAccessException, InvocationTargetException { BeanUtils.copyProperty(bean, name, value); }
	 * 
	 * public static String getProperty(Object bean, String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { return BeanUtils.getProperty(bean, name); }
	 */

	public static boolean isEmpty(Collection<?> collection) {
		if (collection == null || collection.size() == 0) {
			return true;
		} else {
			return false;
		}
	}

	public static boolean isNotEmpty(Collection<?> collection) {
		if (collection != null && collection.size() > 0) {
			return true;
		} else {
			return false;
		}
	}

	public static boolean isNotEmpty(Object[] arrays) {
		if (arrays != null && arrays.length > 0) {
			return true;
		} else {
			return false;
		}
	}


	/**
	 * 反向检查所有的object是否为null，如果都为null 返回true，有一个不为null，并且不等于默认值 返回false boolean：只判断是否为null，无默认值 Long、Integer、Float、double 如果值为null或者是0 Array 判断是否为null或者length=0 Collection判断是否为null或者size=0 Map判断是否null或者siza=0
	 *
	 * @param objs
	 * @return
	 */
	public static boolean reverseCheckAllObjectIsEmpty(Object... objs) {
		if (objs == null || objs.length == 0) {
			return true;
		}

		int count = 0;
		for (Object obj : objs) {
			if (obj == null) {
				count++;
				continue;
			}

			if (obj instanceof Long) {
				Long l = (Long) obj;
				if (l.longValue() == 0L)
					count++;
			} else if (obj instanceof Integer) {
				Integer i = (Integer) obj;
				if (i.intValue() == 0)
					count++;
			} else if (obj instanceof Double) {
				Double d = (Double) obj;
				if (d.doubleValue() == 0.0d)
					count++;
			} else if (obj instanceof Float) {
				Float f = (Float) obj;
				if (f.floatValue() == 0.0f)
					count++;
			} else if (obj.getClass().isArray()) {
				Object[] objArray = (Object[]) obj;
				if (objArray.length == 0)
					count++;
			} else if (obj instanceof Collection) {
				Collection<?> collect = (Collection<?>) obj;
				if (collect.size() == 0)
					count++;
			} else if (obj instanceof Map<?, ?>) {
				Map<?, ?> map = (Map<?, ?>) obj;
				if (map.size() == 0)
					count++;
			} else if (obj instanceof String) {
				String objStr = (String) obj;
				if (objStr.length() == 0)
					count++;
			}
		}
		if (count == objs.length) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 检查传过来的object是否为null，如果有一个为null 则返回false.全部不为null 返回true； (注：如果是List、collection、Map 既要判断是否为空，又要判断是否有数据 | 如果是String 还需要判断String是否为空串)
	 */
	public static boolean checkAllObjectIsEmpty(Object... objs) {
		if (objs == null || objs.length == 0) {
			return true;
		}
		for (Object obj : objs) {
			if (obj == null) {
				return false;
			}
			if (obj.getClass().isArray()) {
				Object[] objArray = (Object[]) obj;
				if (objArray.length == 0) {
					return false;
				}
			} else if (obj instanceof Collection) {
				Collection<?> collect = (Collection<?>) obj;
				if (collect.size() == 0) {
					return false;
				}
			} else if (obj instanceof Map<?, ?>) {
				Map<?, ?> map = (Map<?, ?>) obj;
				if (map.size() == 0) {
					return false;
				}
			} else if (obj instanceof String) {
				String objStr = (String) obj;
				if (objStr.length() == 0) {
					return false;
				}
			}
		}
		return true;
	}


	@SuppressWarnings("rawtypes")
	public static boolean isLegalEnum(Class clazz, Object enuValue) {
		boolean result = false;
		if (null == clazz || null == enuValue) {
			return result;
		}
		if (clazz.isEnum()) {
			Enum[] enums = (Enum[]) clazz.getEnumConstants();
			if (!isEmpty(enums)) {
				if (enuValue instanceof Enum) {
					Enum e = (Enum) enuValue;
					if (Arrays.asList(enums).contains(e)) {
						result = true;
					}
					;
				} else if (enuValue instanceof String) {
					String str = (String) enuValue;
					for (Enum en : enums) {
						if (en.name().equals(str.trim())) {
							result = true;
							break;
						}
					}
				}
			}
		}
		return result;
	}


	/**
	 * 格式化为小数点后两位小数 (offer排序时务必遵守此约定)
	 *
	 * @param o
	 * @return
	 */
	public static String formatDouble(Object o) {
		if (o == null) {
			return "-0.00";
		}
		if (!NumberUtils.isNumber(o.toString())) {
			return "-0.00";
		} else {
			Double value = NumberUtils.createDouble(o.toString());
			return String.format("%.2f", value);
		}
	}

	/**
	 * double 类型的比较器
	 *
	 * @return
	 */
	public static Comparator<Object> doubleComparator() {
		Comparator<Object> c = new Comparator<Object>() {
			@Override
			public int compare(Object o1, Object o2) {
				return Double.valueOf(o1 == null ? "0" : o1.toString()).compareTo(Double.valueOf(o2 == null ? "0" : o2.toString()));
			}
		};
		return c;
	}

	/**
	 * String类型比较规则
	 *
	 * @return
	 */
	public static Comparator<Object> stringComparator() {
		Comparator<Object> c = new Comparator<Object>() {
			@Override
			public int compare(Object o1, Object o2) {
				return o1.toString().compareTo(o2.toString());
			}
		};
		return c;
	}

	public static String listToString(List<?> list) {
		StringBuffer sb = new StringBuffer();
		if (list != null) {
			for (Object obj : list) {
				sb.append(obj);
				sb.append(",");
			}
		}

		String s = sb.toString();
		if (s.endsWith(",")) {
			s = s.substring(0, s.length() - 1);
		}
		return s;
	}

	// Pattern 编译比较耗性能
	private static final String regEx = "(\\?|&+)(.+?)=([^&]*)";
	private static final Pattern p = Pattern.compile(regEx);

	public static Map<String, String> pramsMap(String str) {
		Map<String, String> paramMap = new LinkedHashMap<String, String>();
		Matcher m = p.matcher(str);
		while (m.find()) {
			String paramName = m.group(2);
			String paramVal = m.group(3);
			paramMap.put(paramName, paramVal);
		}
		return paramMap;
	}


	/**
	 * Build queryString
	 */
	public static String buildQueryString(Map<String, String> queryParas) {
		if (queryParas == null || queryParas.isEmpty()) {
			return "";
		}

		StringBuilder sb = new StringBuilder("");
		boolean isFirst = true;

		for (Entry<String, String> entry : queryParas.entrySet()) {
			if (isFirst)
				isFirst = false;
			else
				sb.append("&");

			String key = entry.getKey();
			String value = entry.getValue();
			if (StrKit.notBlank(value))
				try {
					value = URLEncoder.encode(value, CHARSET);
				} catch (UnsupportedEncodingException e) {
					throw new RuntimeException(e);
				}
			sb.append(key).append("=").append(value);
		}
		return sb.toString();
	}

	/**
	 * Build queryString
	 */
	public static String buildQueryStringNoEncode(Map<String, String> queryParas) {
		if (queryParas == null || queryParas.isEmpty()) {
			return "";
		}

		StringBuilder sb = new StringBuilder("");
		boolean isFirst = true;

		for (Entry<String, String> entry : queryParas.entrySet()) {
			if (isFirst)
				isFirst = false;
			else
				sb.append("&");

			String key = entry.getKey();
			String value = entry.getValue();
			if (StrKit.isBlank(value))
				value = "";
			sb.append(key).append("=").append(value);
		}
		return sb.toString();
	}

	/**
	 * 安全的比较两个字符串是否忽略大小写相等，可避免null point exception 若 s1 s2都为null,返回true
	 *
	 * @param s1
	 * @param s2
	 * @return
	 */
	public static boolean equalsIgnoreCase(String s1, String s2) {
		if (s1 == null ^ s2 == null) {
			return false;
		}

		if (s1 != null && s2 != null) {
			return s1.equalsIgnoreCase(s2);
		}

		return true;
	}

	public static String[] toArray(String value) {
		String[] array = {};
		if (StrKit.notBlank(value)) {
			array = value.split(",");
		}
		return array;
	}

	public static Set<String> toSet(String value) {
		HashSet<String> set = new HashSet<String>();
		if (StrKit.notBlank(value)) {
			String[] valueArray = toArray(value);
			set.addAll(Arrays.asList(valueArray));
		}
		return set;
	}

	/**
	 * double相减
	 *
	 * @param d1
	 * @param d2
	 * @return
	 */
	public static Double DoubleSubtract(Double d1, Double d2) {
		BigDecimal b1 = new BigDecimal(Double.toString(d1));
		BigDecimal b2 = new BigDecimal(Double.toString(d2));
		return b1.subtract(b2).doubleValue();
	}

	/**
	 * double 相加
	 *
	 * @param d1
	 * @param d2
	 * @return
	 */
	public static Double DoubleAdd(Double d1, Double d2) {
		BigDecimal b1 = new BigDecimal(Double.toString(d1));
		BigDecimal b2 = new BigDecimal(Double.toString(d2));
		return b1.add(b2).doubleValue();
	}

	/**
	 * double 除法
	 */
	public static Double DoubleDivide(Double d1, Double d2) {
		BigDecimal b1 = new BigDecimal(Double.toString(d1));
		BigDecimal b2 = new BigDecimal(Double.toString(d2));
		return b1.divideToIntegralValue(b2).doubleValue();

	}

	public static Map<String, String> queryStringMap(String str) {
		Map<String, String> paramMap = new LinkedHashMap<String, String>();
		if (!str.startsWith("?")) {
			str = "?" + str;
		}
		Matcher m = p.matcher(str);
		while (m.find()) {
			String paramName = m.group(2);
			String paramVal = m.group(3);
			paramMap.put(paramName, paramVal);
		}
		return paramMap;
	}

	/**
	 * 按照步长切割字符串
	 *
	 * @param str
	 * @param step
	 * @return
	 * @author dpc
	 */
	public static String[] splitByStep(String str, int step) {
		if (step <= 0) {
			throw new ArithmeticException(" / by zero ");
		}
		int length = str.length();
		int count = length % step == 0 ? length / step : length / step + 1;
		String[] array = new String[count];
		for (int i = 0; i < count; i++) {
			int start = i * step;
			int end = i * step + step;
			if (length < end)
				end = length;
			array[i] = str.substring(start, end);
		}
		return array;
	}

	/**
	 * 匹配一组由大括号包裹的参数
	 *
	 * 输入：{123},xxx{456}xxx,,,{789}
	 *
	 * 输出：[123, 456, 789]
	 * @param expression
	 * @author dpc
	 * @return
	 */
	public static List<String> getBigBracesList(String expression) {
		List<String> ls = new ArrayList<String>();
		Pattern pattern = Pattern.compile("(?<=\\{)(.+?)(?=\\})");
		Matcher matcher = pattern.matcher(expression);
		while (matcher.find())
			ls.add(matcher.group());
		return ls;
	}
}
